package org.example.javax.crypto;

import java.security.Key;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;


/**
 * DES安全编码组件
 * <p/>
 * <pre>
 * 支持 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)
 * DES          		key size must be equal to 56
 * DESede(TripleDES) 	key size must be equal to 112 or 168
 * AES          		key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
 * Blowfish     		key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
 * RC2          		key size must be between 40 and 1024 bits
 * RC4(ARCFOUR) 		key size must be between 40 and 1024 bits
 * 具体内容 需要关注 JDK Document http://.../docs/technotes/guides/security/SunProviders.html
 * </pre>
 */
public class DESCoder extends Coder {
  /**
   * ALGORITHM 算法 <br>
   * 可替换为以下任意一种算法，同时key值的size相应改变。
   * <p/>
   * <pre>
   * DES          		key size must be equal to 56
   * DESede(TripleDES) 	key size must be equal to 112 or 168
   * AES          		key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
   * Blowfish     		key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
   * RC2          		key size must be between 40 and 1024 bits
   * RC4(ARCFOUR) 		key size must be between 40 and 1024 bits
   * </pre>
   * <p/>
   * 在Key toKey(byte[] key)方法中使用下述代码
   * <code>SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);</code> 替换
   * <code>
   * DESKeySpec dks = new DESKeySpec(key);
   * SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
   * SecretKey secretKey = keyFactory.generateSecret(dks);
   * </code>
   */
  public static final String ALGORITHM = "DES";

  /**
   * 转换密钥<br>
   *
   * @param key
   * @return
   * @throws Exception
   */
  private static Key toKey(byte[] key) throws Exception {
    DESKeySpec dks = new DESKeySpec(key);
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
    SecretKey secretKey = keyFactory.generateSecret(dks);

    // 当使用其他对称加密算法时，如AES、Blowfish等算法时，用下述代码替换上述三行代码
    // SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);

    return secretKey;
  }

  /**
   * 解密
   *
   * @param data
   * @param key
   * @return
   * @throws Exception
   */
  public static byte[] decrypt(byte[] data, String key) throws Exception {
    Key k = toKey(decryptBASE64(key));

    Cipher cipher = Cipher.getInstance(ALGORITHM);
    cipher.init(Cipher.DECRYPT_MODE, k);

    return cipher.doFinal(data);
  }

  /**
   * 加密
   *
   * @param data
   * @param key
   * @return
   * @throws Exception
   */
  public static byte[] encrypt(byte[] data, String key) throws Exception {
    Key k = toKey(decryptBASE64(key));
    Cipher cipher = Cipher.getInstance(ALGORITHM);
    cipher.init(Cipher.ENCRYPT_MODE, k);

    return cipher.doFinal(data);
  }

  /**
   * 生成密钥
   *
   * @return
   * @throws Exception
   */
  public static String initKey() throws Exception {
    return initKey(null);
  }

  /**
   * 生成密钥
   *
   * @param seed
   * @return
   * @throws Exception
   */
  public static String initKey(String seed) throws Exception {
    SecureRandom secureRandom = null;

    if (seed != null) {
      secureRandom = new SecureRandom(decryptBASE64(seed));
    } else {
      secureRandom = new SecureRandom();
    }

    KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
    kg.init(secureRandom);

    SecretKey secretKey = kg.generateKey();

    return encryptBASE64(secretKey.getEncoded());
  }
}

